<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<meta name="copyright" content="Copyright (c) GK Software AG and others 2012. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." >
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css">
<link rel="stylesheet" href="../book.css" charset="ISO-8859-1" type="text/css">
<style type="text/css">
	div.recommendation { margin-left:10px;margin-right:10px; background-color:#f0f0f0; padding:10px; }
	div.recommendation strong { color:green; }
</style>
<title>Ensuring completeness of switch statements</title>
</head>
<body>
<h1> Ensuring completeness of switch statements </h1>
<p>
It is good practice to ensure that each <code>switch</code> statement should be complete
in the sense that each execution at run time will find a suitable branch.
This is actually a non-trivial task when taking all of the following into consideration:
</p>
<ul>
<li>Different rules apply for switches over an <b>enum</b> value vs. int or even String.</li>
<li>Depending on the context, using a <b>default</b> label may appear undesirable or good practice or even mandatory.</li>
<li>In some contexts <b>program evolution</b> should be safe guarded by flagging inconsistent extension as an error,
	while in other contexts a more forgiving strategy is desirable.</li>  
</ul>
<p>
Additionally, the JLS mandates a flow analysis for enum switch statements which can lead to unexpected
compile time errors:
<pre id="missing_return">    enum Colors { RED, GREEN, BLUE }
    String colorString(Color c) {
        switch(c) {
            case RED: return "red";
            case GREEN: return "green";
            case BLUE: return "blue";
        }
    }
</pre>
<p>
The compiler will answer:</p>
<blockquote>"This method must return a result of type String.
 Note that a problem regarding missing 'default:' on 'switch' has been suppressed, which is perhaps related to this problem".</blockquote>
<p>
This message has been designed to alert users of the different notions of completeness:
	the flow analysis mandated by the JLS considers <em>each</em> enum switch statement without a default case as incomplete,
	even if it lists all (currently known) enum constants. This concerns return statements as well as definite assignment
	of local variables or blank final fields.
	However, if you follow all recommendations below, the above error message will never occur.
</p>
<p>Please consult the <a href="../reference/preferences/java/compiler/ref-preferences-errors-warnings.htm#switch">compiler preferences</a> regarding the individual configuration options
	for reporting various levels of incompleteness. In the sequel we discuss different design goals and policies
	and how they can be checked using the Eclipse Java compiler.
</p>
<h2>On using "default:"</h2>
<p>Optimally, each switch statement should have a <b>meaningful default branch</b>,
	which handles all cases that are not explicitly listed using an "always-reasonable" strategy.
	Obviously, such a strategy is difficult or even impossible to find in many cases,
	but if you can find a meaningful default implementation, that's certainly the best solution.
</p>
<div class="recommendation">
	<strong>Recommendation:</strong> By letting the compiler warn you about each switch statement lacking a default case
	you are reminded to search for a good default implementation for every switch statement.
</div>
<p>If the compiler warns you about a missing default case, but the reasonable thing to do by default
	is just <b>do nothing</b>, this might as well be worth documenting.
</p>
<div class="recommendation">
	<strong>Recommendation:</strong> If "do nothing" is a reasonable default strategy you should
	add a <code>default:</code> label whose action is only a comment explaining that (and why)
	doing nothing is OK in this switch. By doing so you also tell the compiler that you did not
	simply <em>forget</em> about a default case.
</div>
<p>If definitely no reasonable default implementation can be found, as a <b>last resort</b> you
	may want to prevent an unexpected value to be the root cause for other errors further downstream,
	i.e., you may want to <b>fail early</b> at runtime.
</p>
<div class="recommendation">
	<strong>Recommendation:</strong> If neither a reasonable default implementation can be found
	nor "do nothing" appears to be a good strategy, add a <code>default:</code> case that throws
	an exception and/or logs the problem.
</div>
<p>Each switch statement should be assignable to one of the three above categories.
	This means letting the compiler <b>warn you about each missing default case</b>
	is a universally valid strategy. 
</p>
<h2>Handling all enum constants</h2>
<p>When performing a switch over an enum value, it may be desirable to explicitly cover
	each enum constant by a corresponding case statement.
</p>
<div class="recommendation">
	<strong>Recommendation:</strong> If you want to be warned about enum switch statements
	that lack a case statement for any of the enum constants, please consider enabling the option
	<a href="../reference/preferences/java/compiler/ref-preferences-errors-warnings.htm#missing_case_despite_default">Signal even if 'default' case exists</a>.
</div>
<p>If you don't like the option that <em>all</em> enum switches should mention all enum constants,
	but still want to get the warning about missing case labels for <em>some</em> enum switch statements,
	you'll need to select the strategy for each individual enum switch statement.
</p>
<div class="recommendation">
	<strong>Recommendation:</strong> If the above warning is desirable for some switch statements,
	consider to globally enable the warning, and identify those switch statements where it is OK
	to <em>omit</em> cases for some enum constants, because those are suitably handled by the default case. 
	For these switch statements use the '//$CASES-OMITTED$' tag comment to document your decision:
</div>
<pre>    String colorString2(Color c) {
        switch(c) {
        case RED: return "red";
        case GREEN: return "green";
            //$CASES-OMITTED$
        default:
        	return "unknown color";
        }
    }</pre>
<p><strong>Hint:</strong> If the compiler reports something like 
	"The enum constant BLUE should have a corresponding case label in this enum switch on Color"
	a quick fix will be offered for inserting the tag comment.
</p>
<h2>Summary</h2>
<p>The above considerations have shown that you get most help from the compiler if you <b>enable all optional warnings</b>
	regarding incomplete switch statements, and use empty documented default cases plus <code>//$CASES-OMITTED$</code> tag comments
	to mark those switch statements where incompleteness is OK by design.
	If you follow these recommendations, you will get all relevant warnings (or errors if you like)
	when branches are accidentally omitted, including the situation of late addition of one or more enum constants.
	All exceptions from this maximum completeness will be documented in the code and no longer flagged with a warning.
</p>
<p>Still the compiler cannot prevent the use of inconsistent class versions at runtime,
	so a class may be compiled against an old version of an enum type, but in the running
	application the enum type may have more enum constants.
	For these and similar situations an appropriate "catch-all" default implementations
	can raise runtime exceptions to alert of this inconsistency and prevent the error from
	propagating further into the application. 
</p>
<p>As an added value of the strict compiler settings recommended above, the dubious error message
	about a missing return statement <a href="#missing_return">shown above</a> 
	(or similar messages about uninitialized variables) will no longer occur.
</p>
</body>
</html>
